package com.github.xzb617.utils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.*;

@SuppressWarnings("all")
public class ReflectUtil {


    /**
     * 获取类及其父类的所有属性名（终止类为 Object.class）
     * @param clazz 目标类
     * @return
     */
    public static List<Field> getFields(Class<?> clazz) {
        List<Field> fieldList = new ArrayList<>();
        // 当目标类的父类为null，则说明其已经是 Object.class
        while (clazz!=null && clazz.getSuperclass()!=null) {
            Field[] fields = clazz.getDeclaredFields();
            if (fields.length > 0) {
                fieldList.addAll(CollectionUtil.arrayToList(fields));
            }
            clazz = clazz.getSuperclass();
        }
        return fieldList;
    }


    public static Object getFieldValue(Field field, Object object) throws IllegalAccessException {
        Object value = null;
        if (!field.isAccessible()) {
            field.setAccessible(true);
            value = field.get(object);
            field.setAccessible(false);
        } else {
            value =  field.get(object);
        }
        return value;
    }


    public static Object getFieldValue(String fieldName, Object object)
                                            throws IllegalAccessException, NoSuchFieldException {
        Field field = object.getClass().getDeclaredField(fieldName);
        Object value = null;
        if (!field.isAccessible()) {
            field.setAccessible(true);
            value = field.get(object);
            field.setAccessible(false);
        } else {
            value =  field.get(object);
        }
        return value;
    }

    public static Object getFieldValue(Class<? extends Annotation> anno, Object object)
            throws IllegalAccessException, IllegalArgumentException, NoSuchFieldException {
        Field[] declaredFields = object.getClass().getDeclaredFields();
        boolean flag = false;
        Object result = null;
        for (Field field : declaredFields) {
            if (!field.isAccessible()) {
                field.setAccessible(true);
            }
            Annotation annotation = field.getAnnotation(anno);
            if (annotation != null) {
                flag = true;
                result = field.get(object);
                break;
            }
        }
        if (!flag) {
            throw new NoSuchFieldException("Annotation " + anno.getName() + " can not found in any field");
        }
        return result;
    }


    public static void setFieldValue(Field field, Object object, Object value) throws IllegalAccessException {
        if (!field.isAccessible()) {
            field.setAccessible(true);
            field.set(object, value);
            field.setAccessible(false);
        } else {
            field.set(object, value);
        }
    }


    public static void setFieldValue(String fieldName, Object object, Object value)
                                        throws IllegalAccessException, NoSuchFieldException {
        Field field = object.getClass().getDeclaredField(fieldName);
        if (!field.isAccessible()) {
            field.setAccessible(true);
            field.set(object, value);
            field.setAccessible(false);
        } else {
            field.set(object, value);
        }
    }


    public static void setFieldValue(Class<? extends Annotation> anno, Object object, Object value)
            throws IllegalAccessException, IllegalArgumentException, NoSuchFieldException {
        Field[] declaredFields = object.getClass().getDeclaredFields();
        boolean result = false;
        for (Field field : declaredFields) {
            if (!field.isAccessible()) {
                field.setAccessible(true);
            }
            Annotation annotation = field.getAnnotation(anno);
            if (annotation != null) {
                result = true;
                field.set(object, value);
                break;
            }
        }
        if (result == false) {
            throw new NoSuchFieldException("Annotation " + anno.getName() + " can not found in any field");
        }
    }


    public static boolean hasField(String fieldName, Class<?> targetClass) {
        try {
            targetClass.getDeclaredField(fieldName);
        } catch (NoSuchFieldException e) {
            return false;
        }
        return true;
    }

}
